package db

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"

	"xlib/log"

	B "github.com/go-xorm/builder"
	"github.com/go-xorm/xorm"
	uuid "github.com/satori/go.uuid"

	D "TCP/define"
)

const emptySlots string = `[{"begin":"00:00","end":"00:00"}]`

//DacConn API相关的数据库连接
type DacConn struct {
	driver string
	source string
	dbConn *xorm.Engine
}

//NewDacConn DacConn的构造函数
func NewDacConn() *DacConn {
	ac := &DacConn{}
	ac.init()
	return ac
}

func (ac *DacConn) init() {
	ac.dbConn = GetConn(ac.driver, ac.source)
	session := ac.dbConn.NewSession()
	defer session.Close()

	tableExist, err := session.IsTableExist(new(DrvInfo))
	if err != nil {
		log.Errorf("Engine xorm fail, err = %s", err)
	}
	//新建缓存表
	if !tableExist {
		err = session.Sync2(new(DrvInfo))
		if err != nil {
			log.Errorf("Engine create DrvInfo fail, err = %s", err)
			return
		} else {
			log.Infof("Engine create DrvInfo success")
		}
	}
	tableExist, err = session.IsTableExist(new(DrvEvent))
	if err != nil {
		log.Errorf("Engine xorm fail, err = %s", err)
	}
	//新建缓存表
	if !tableExist {
		err = session.Sync2(new(DrvEvent))
		if err != nil {
			log.Errorf("Engine create DrvEvent fail, err = %s", err)
			return
		} else {
			log.Infof("Engine create DrvEvent success")
		}
	}
}

//GetDrvInfo 获取设备信息数据
func (ac *DacConn) GetDrvInfo(sn string) (DrvInfo, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	drvInfo := &DrvInfo{SN: sn}
	exist, err := session.Get(drvInfo)
	if err != nil {
		log.Error(err)
		return DrvInfo{}, err
	}
	if !exist {
		log.Warnf("get [%s] DrvInfo fail, there is no info", sn)
		return DrvInfo{}, errors.New(fmt.Sprintf("get [%s] DrvInfo fail, there is no info", sn))
	}
	return *drvInfo, nil
}

//GetCSQRecord 获取信号强度历史数据
func (ac *DacConn) GetCSQRecord(sn string) ([]DrvEvent, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	csq := &DrvEvent{
		SN:      sn,
		Type:    2,
		EventID: "08",
	}
	drvEvents := make([]DrvEvent, 0)
	err := session.Desc("event_time").Limit(50).Find(&drvEvents, csq)
	if err != nil {
		log.Error(err)
		return []DrvEvent{}, err
	}

	return drvEvents, nil
}

//SaveDrvInfo 保存设备信息数据
func (ac *DacConn) SaveDrvInfo(info DrvInfo) error {
	session := ac.dbConn.NewSession()
	defer session.Close()

	if err := session.Begin(); err != nil {
		log.Error(err)
		return err
	}

	drvInfo := &DrvInfo{SN: info.SN}
	exist, err := session.Get(drvInfo)
	if err != nil {
		log.Error(err)
		return err
	}
	if exist {
		_, err = session.Where(B.In("sn", info.SN)).Update(&info)
		if err != nil {
			log.Error(err)
			_ = session.Rollback()
			return err
		}
		log.Debugf("Update [%s] DrvInfo success", info.SN)
	} else {
		_, err := session.InsertOne(info)
		if err != nil {
			log.Error(err)
			_ = session.Rollback()
			return err
		} else {
			log.Debugf("Insert [%s] DrvInfo success", info.SN)
		}
	}

	if err := session.Commit(); err != nil {
		log.Error(err)
		return err
	}
	return nil
}

//SaveDrvEvent 保存设备信息事件
func (ac *DacConn) SaveDrvEvent(events []DrvEvent) error {
	session := ac.dbConn.NewSession()
	defer session.Close()

	if err := session.Begin(); err != nil {
		log.Error(err)
		return err
	}

	for index, event := range events {
		_, err := session.InsertOne(event)
		if err != nil {
			log.Errorf("Insert [%s] DrvEvent fail,index:%d", event.SN, index)
		}
	}
	if err := session.Commit(); err != nil {
		log.Error(err)
		return err
	}
	return nil
}

/*
* Door: include get_doors, get_door_state
 */

//GetDoors 获取门信息
func (ac *DacConn) GetDoors() ([]AcsDoor, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	doors := make([]AcsDoor, 0)
	err := session.Where(B.Neq{"modify": D.Delete}).Find(&doors)
	if err != nil {
		log.Error(err)
		return doors, err
	}

	return doors, nil
}

//GetDoorByNo 获取门信息
func (ac *DacConn) GetDoorByNo(controllerID string, doorNo int) (AcsDoor, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	door := AcsDoor{ControllerID: controllerID, DoorNo: doorNo}
	_, err := session.Where(B.Neq{"modify": D.Delete}).Get(&door)
	if err != nil {
		log.Error(err)
		return door, err
	}

	return door, nil
}

func (ac *DacConn) GetDoorByNos(doorNos []int) ([]AcsDoor, error) {
	session := ac.dbConn.NewSession()
	doors := make([]AcsDoor, 0)
	err := session.Where(B.Neq{"modify": D.Delete}).And(B.In("door_no", doorNos)).Find(&doors)
	if err != nil {
		log.Error(err)
		return doors, err
	}

	return doors, nil
}

func (ac *DacConn) getDoorByIDs(doorIDs []int) ([]*AcsDoor, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	var where B.Cond = B.Neq{"modify": D.Delete}
	if len(doorIDs) != 0 {
		where = where.And(B.In("door_id", doorIDs))
	}

	doors := make([]*AcsDoor, 0)
	err := session.Where(where).Find(&doors)
	if err != nil {
		log.Error(err)
		return doors, err
	}

	return doors, nil
}

//GetDoorByTimePris 通过权限信息获取门信息
func (ac *DacConn) GetDoorByTimePris(timePris []*AcsTimePrivilege) ([]int, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	var where B.Cond = B.Neq{"modify": D.Delete}
	if len(timePris) == 0 {
		return nil, errors.New("invalid parameter: time_pris is nil")
	}

	ctlDoors := make([]string, 0)
	for _, tp := range timePris {
		key := fmt.Sprintf("%s_%d", tp.ControllerID, tp.DoorNo)
		ctlDoors = append(ctlDoors, key)
	}
	where = where.And(B.In(`CONCAT_WS("_", controller_id, door_no)`, ctlDoors))

	doorIDs := make([]int, 0)
	err := session.Cols("door_id").Table("acs_door").Where(where).Find(&doorIDs)
	if err != nil {
		log.Error(err)
		return doorIDs, err
	}

	return doorIDs, nil
}

/*
* OpenTime: include get_time_group, set_time_group, clear_time_group
 */

func (ac *DacConn) getOpenIDByGroupNo(groupNo int) ([]string, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	openIDs := make([]string, 0)
	openIndex := []int{groupNo * 3, groupNo*3 + 1, groupNo*3 + 2}

	where := B.And(B.In("open_index", openIndex), B.Neq{"modify": D.Delete})
	err := session.Distinct("open_id").Table("acs_door_time").Where(where).Find(&openIDs)
	if err != nil {
		log.Error(err)
		return openIDs, err
	}

	return openIDs, err
}

func (ac *DacConn) getDoorTimeByOpenIndexAndDoor(session *xorm.Session, openIndex int, doors []*AcsDoor) ([]*AcsDoorTime, error) {
	dts := make([]*AcsDoorTime, 0)
	err := session.Where(B.And(B.Eq{"open_index": openIndex}, B.Neq{"modify": D.Delete})).Find(&dts)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	doorTimes := make([]*AcsDoorTime, 0)
	ds := make([]*AcsDoor, 0)
	for _, door := range doors {
		hitFlag := false
		for _, dt := range dts {
			if door.ControllerID == dt.ControllerID && door.DoorNo == dt.DoorNo {
				doorTimes = append(doorTimes, dt)
				hitFlag = true
				break
			}
		}

		if !hitFlag {
			ds = append(ds, door)
		}
	}

	dss, err := ac.setEmptyOpenTimeForDoors(session, openIndex, ds)
	if err != nil {
		log.Error(err)
		return dts, err
	}

	doorTimes = append(doorTimes, dss...)
	return doorTimes, err
}

//GetOpenTime 获取时段信息
func (ac *DacConn) GetOpenTime(groupNo int) ([]*AcsOpenTime, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	openTimes := make([]*AcsOpenTime, 0)

	openIDs, err := ac.getOpenIDByGroupNo(groupNo)
	if err != nil {
		log.Error(err)
		return openTimes, err
	}

	err = session.Where(B.And(B.In("open_id", openIDs), B.Neq{"modify": D.Delete})).Limit(3).Find(&openTimes)
	if err != nil {
		log.Error(err)
		return openTimes, err
	}

	return openTimes, err
}

func (ac *DacConn) setEmptyOpenTimeForDoors(session *xorm.Session, openIndex int, doors []*AcsDoor) ([]*AcsDoorTime, error) {
	dts := make([]*AcsDoorTime, 0)
	if len(doors) == 0 {
		return dts, nil
	}

	openTime := &AcsOpenTime{
		OpenID:    uuid.NewV4().String(),
		TimeName:  fmt.Sprintf("时段%d", openIndex),
		TimeSlots: emptySlots,
		Identify:  1,
		Modify:    D.Add,
	}

	_, err := session.InsertOne(openTime)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	for _, door := range doors {
		dt := &AcsDoorTime{
			ControllerID: door.ControllerID,
			DoorNo:       door.DoorNo,
			OpenIndex:    openIndex,
			OpenID:       openTime.OpenID,
			Modify:       D.Add,
		}
		dts = append(dts, dt)
	}

	_, err = session.Insert(dts)
	if err != nil {
		log.Error(err)
		return dts, err
	}

	return dts, nil
}

func (ac *DacConn) buildTimeSlots(timeInfo D.TimeInfo, ots []*AcsOpenTime) ([]string, error) {
	ts := make([]string, 0)

	if len(timeInfo.Timezone) != 0 {
		for i := 0; i < 3; i++ {
			if i < len(timeInfo.Timezone) {
				s, err := json.Marshal(timeInfo.Timezone[i])
				if err != nil {
					log.Error(err)
					return ts, err
				}

				ts = append(ts, fmt.Sprintf(`[%s]`, string(s)))
			} else {
				ts = append(ts, emptySlots)
			}
		}
		return ts, nil
	}

	for i := 0; i < 3; i++ {
		if i < len(ots) {
			ts = append(ts, ots[i].TimeSlots)
		} else {
			ts = append(ts, emptySlots)
		}
	}

	return ts, nil
}

func (ac *DacConn) buildTimePriMap(tps []*AcsTimePrivilege) map[int][]*AcsTimePrivilege {
	tpMap := make(map[int][]*AcsTimePrivilege, 0)

	for _, tp := range tps {
		if _, ok := tpMap[tp.OpenIndex]; !ok {
			tpMap[tp.OpenIndex] = make([]*AcsTimePrivilege, 0)
		}
		tpMap[tp.OpenIndex] = append(tpMap[tp.OpenIndex], tp)
	}

	return tpMap
}

func (ac *DacConn) setWeekInfo(week []int, acsOpenTime *AcsOpenTime) {
	if week == nil || acsOpenTime == nil {
		log.Error("invalid parameter")
		return
	}

	for _, w := range week {
		switch w {
		case 1:
			acsOpenTime.IsMonday = 1
		case 2:
			acsOpenTime.IsTuesday = 1
		case 3:
			acsOpenTime.IsWednesday = 1
		case 4:
			acsOpenTime.IsThursday = 1
		case 5:
			acsOpenTime.IsFriday = 1
		case 6:
			acsOpenTime.IsSaturday = 1
		case 7:
			acsOpenTime.IsSunday = 1
		default:
			continue
		}
	}
}

func (ac *DacConn) getTimeRelated(session *xorm.Session, groupNo int) ([]*AcsOpenTime, []*AcsTimePrivilege, []AcsDoor, error) {
	ots, tps, err := ac.deleteOpenTimeByGroupNo(session, groupNo)
	if err != nil {
		log.Error(err)
		return nil, nil, nil, err
	}

	doors, err := ac.GetDoors()
	if err != nil {
		log.Error(err)
		return ots, tps, doors, err
	}

	return ots, tps, doors, nil
}

//SetOpenTime 设置时段
func (ac *DacConn) SetOpenTime(timeInfo D.TimeInfo) error {
	session := ac.dbConn.NewSession()
	defer session.Close()

	if timeInfo.Week == nil && timeInfo.Timezone == nil {
		return nil
	}

	if err := session.Begin(); err != nil {
		log.Error(err)
		return err
	}
	ots, tps, doors, err := ac.getTimeRelated(session, timeInfo.GroupNo)
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	tpMap := ac.buildTimePriMap(tps)
	ts, err := ac.buildTimeSlots(timeInfo, ots)
	if err != nil {
		log.Error(err)
		return err
	}

	acsOpenTime := &AcsOpenTime{
		Identify: 1,
		Modify:   D.Add,
	}
	if timeInfo.Week != nil {
		ac.setWeekInfo(timeInfo.Week, acsOpenTime)
	} else {
		if len(ots) > 0 {
			acsOpenTime.IsMonday = ots[0].IsMonday
			acsOpenTime.IsTuesday = ots[0].IsTuesday
			acsOpenTime.IsWednesday = ots[0].IsWednesday
			acsOpenTime.IsThursday = ots[0].IsThursday
			acsOpenTime.IsFriday = ots[0].IsFriday
			acsOpenTime.IsSaturday = ots[0].IsSaturday
			acsOpenTime.IsSunday = ots[0].IsSunday
		}
	}

	for i := 0; i <= 2; i++ {
		var aot = new(AcsOpenTime)
		*aot = *acsOpenTime
		aot.OpenID = uuid.NewV4().String()
		aot.TimeName = fmt.Sprintf("时段%d", timeInfo.GroupNo*3+i)
		aot.TimeSlots = ts[i]
		log.Info("set aot: %#v", *aot)
		_, err := session.InsertOne(aot)
		if err != nil {
			log.Error(err)
			_ = session.Rollback()
			return err
		}

		dts := make([]*AcsDoorTime, 0)
		for _, door := range doors {
			dt := &AcsDoorTime{
				ControllerID: door.ControllerID,
				DoorNo:       door.DoorNo,
				OpenIndex:    timeInfo.GroupNo*3 + i,
				OpenID:       aot.OpenID,
				Modify:       D.Add,
			}
			dts = append(dts, dt)
		}

		_, err = session.Insert(dts)
		if err != nil {
			log.Error(err)
			_ = session.Rollback()
			return err
		}

		if tips, ok := tpMap[i]; ok && len(tips) > 0 {
			for _, tip := range tips {
				tip.OpenID = aot.OpenID
			}

			_, err = session.Insert(tips)
			if err != nil {
				log.Error(err)
				_ = session.Rollback()
				return err
			}
		}
	}

	if err := session.Commit(); err != nil {
		log.Error(err)
		return err
	}

	return nil
}

func (ac *DacConn) deleteOpenTimeByGroupNo(session *xorm.Session, groupNo int) ([]*AcsOpenTime, []*AcsTimePrivilege, error) {
	openIDs := make([]string, 0)
	openIndex := []int{groupNo * 3, groupNo*3 + 1, groupNo*3 + 2}

	where := B.And(B.In("open_index", openIndex), B.Neq{"modify": D.Delete})
	err := session.Distinct("open_id").Table("acs_door_time").Where(where).Find(&openIDs)
	if err != nil {
		log.Error(err)
		return nil, nil, err
	}

	openTimes := make([]*AcsOpenTime, 0)
	timePris := make([]*AcsTimePrivilege, 0)

	w1 := B.And(B.In("open_id", openIDs), B.Neq{"modify": D.Delete})
	err = session.Where(w1).Asc("update_time").Limit(3).Find(&openTimes)
	if err != nil {
		log.Error(err)
		return openTimes, timePris, err
	}

	w2 := w1.And(B.In("open_index", openIndex))
	err = session.Distinct("controller_id", "door_no", "open_index", "group_id").Where(w2).Find(&timePris)
	if err != nil {
		log.Error(err)
		return openTimes, timePris, err
	}

	_, err = session.Where(B.In("open_id", openIDs)).Delete(&AcsOpenTime{})
	if err != nil {
		log.Error(err)
		return openTimes, timePris, err
	}

	return openTimes, timePris, nil
}

//DeleteOpenTime 删除时段
func (ac *DacConn) DeleteOpenTime(groupNo int) error {
	session := ac.dbConn.NewSession()
	defer session.Close()

	if err := session.Begin(); err != nil {
		log.Error(err)
		return err
	}

	openIDs, err := ac.getOpenIDByGroupNo(groupNo)
	if err != nil {
		log.Error(err)
		return err
	}

	_, err = session.Where(B.In("open_id", openIDs)).Update(&AcsOpenTime{Modify: D.Delete})
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	_, err = session.Where(B.In("open_id", openIDs)).Update(&AcsDoorTime{Modify: D.Delete})
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	_, err = session.Where(B.In("open_id", openIDs)).Update(&AcsTimePrivilege{Modify: D.Delete})
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	if err := session.Commit(); err != nil {
		log.Error(err)
		return err
	}

	return nil
}

/*
* Card: include get_cards, get_card, add_card, modify_card, delete_card
 */

//GetCards 获取卡信息
func (ac *DacConn) GetCards(cardID string) ([]*AcsCard, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	cards := make([]*AcsCard, 0)
	where := B.In("modify", []int{D.Normal, D.Add, D.Change})
	if cardID != "" {
		where = where.And(B.Eq{"card_id": strings.TrimLeft(cardID, "0")})
	}

	err := session.Where(where).Find(&cards)
	if err != nil {
		log.Error(err)
		return cards, err
	}

	return cards, nil
}

//AddCard 新增卡
func (ac *DacConn) AddCard(cardInfo D.CardInfo) error {
	session := ac.dbConn.NewSession()
	defer session.Close()

	cardID := strings.TrimLeft(cardInfo.CardNo, "0")
	card := &AcsCard{CardID: cardID}
	exist, err := session.Get(card)
	if err != nil {
		log.Error(err)
		return err
	}

	card.CardStatus = cardInfo.CardFlag + 1 // 向前兼容，数据库里是1,2；接口传过来的是0,1
	card.CardType = D.Guest
	card.OriginCardID = cardInfo.CardNo
	card.PersonName = cardInfo.UserName
	card.CardPwd = cardInfo.Password
	card.Deadline = time.Now().AddDate(20, 0, 0)
	card.Modify = D.Add
	if exist {
		return ac.SetCard(cardInfo)
	}

	if err := session.Begin(); err != nil {
		log.Error(err)
		return err
	}

	c := &AcsCard{}
	exist, err = session.Where(B.Eq{"modify": D.Invalid}).Asc("card_index").Get(c)
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
	}

	if exist {
		_, err := session.Update(card, c)
		if err != nil {
			log.Error(err)
			_ = session.Rollback()
			return err
		}
	} else {
		_, err := session.InsertOne(card)
		if err != nil {
			log.Error(err)
			_ = session.Rollback()
			return err
		}
	}

	err = ac.addPrivilegeGroup(session, cardInfo)
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	if err := session.Commit(); err != nil {
		log.Error(err)
		return err
	}

	return nil
}

func (ac *DacConn) resetCardAndPersonRelation(session *xorm.Session, cardID string) error {
	where := B.Neq{"modify": D.Delete}
	cp := &AcsCardPerson{CardID: cardID}
	exist, err := session.Where(where).Get(cp)
	if err != nil {
		log.Error(err)
		return err
	}

	if exist {
		_, err = session.Where(B.Eq{"person_number": cp.PersonNumber}).Update(&AcsCardPerson{Modify: D.Delete})
		if err != nil {
			log.Error(err)
			return err
		}

		_, err = session.Where(B.Eq{"item_id": cp.PersonNumber}).Update(&AcsPrivilegeItem{Modify: D.Delete})
		if err != nil {
			log.Error(err)
			return err
		}
	}

	return nil
}

//SetCard 设置卡
func (ac *DacConn) SetCard(cardInfo D.CardInfo) error {
	session := ac.dbConn.NewSession()
	defer session.Close()

	if err := session.Begin(); err != nil {
		log.Error(err)
		return err
	}

	cardID := strings.TrimLeft(cardInfo.CardNo, "0")
	err := ac.resetCardAndPersonRelation(session, cardID)
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	card := &AcsCard{
		PersonName:   cardInfo.UserName,
		CardID:       cardID,
		OriginCardID: cardInfo.CardNo,
		CardPwd:      cardInfo.Password,
		CardType:     D.Guest,
		CardStatus:   cardInfo.CardFlag + 1, // 腾讯规定这里传过来的是0正常，1停用 我们系统里面存的是1,2，向前兼容+1
		Deadline:     time.Now().AddDate(20, 0, 0),
		Modify:       D.Add,
	}

	_, err = session.Update(card, &AcsCard{CardID: cardID})
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	err = ac.setPrivilegeGroup(session, cardInfo)
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	if err := session.Commit(); err != nil {
		log.Error(err)
		return err
	}

	return nil
}

//DeleteCard 删除卡号
func (ac *DacConn) DeleteCard(cardNo string) error {
	session := ac.dbConn.NewSession()
	defer session.Close()

	cardID := strings.TrimLeft(cardNo, "0")

	if err := session.Begin(); err != nil {
		log.Error(err)
		return err
	}

	card := &AcsCard{CardID: cardID}
	_, err := session.Update(&AcsCard{Modify: D.Delete}, card)
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	priItem := &AcsPrivilegeItem{ItemID: cardID, ItemType: D.Person}
	_, err = session.Update(&AcsPrivilegeItem{Modify: D.Delete}, priItem)
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	pri := &AcsPrivilegeGroup{GroupName: "CARD_" + cardID}
	_, err = session.Update(&AcsPrivilegeGroup{Modify: D.Delete}, pri)
	if err != nil {
		log.Error(err)
		_ = session.Rollback()
		return err
	}

	if err := session.Commit(); err != nil {
		log.Error(err)
		return err
	}

	return nil
}

/*
* Privilege: include add_privilege, set_privilege
 */

//GetPrivilegeByCard 获取卡号相关的权限
func (ac *DacConn) GetPrivilegeByCard(cardNo string) ([]*AcsTimePrivilege, error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	cardID := strings.TrimLeft(cardNo, "0")
	privileges := make([]*AcsTimePrivilege, 0)
	where := B.Neq{"modify": D.Delete}

	cp := &AcsCardPerson{CardID: cardID}
	exist, err := session.Where(where).Get(cp)
	if err != nil {
		log.Error(err)
		return privileges, err
	}

	var w1 B.Cond = where
	if exist {
		w1 = w1.And(B.Eq{"item_id": cp.PersonNumber})
	} else {
		w1 = w1.And(B.Eq{"item_id": cardID})
	}

	//TODO 改成join
	privilegeIDs := make([]string, 0)
	err = session.Distinct("group_id").Table("acs_privilege_item").Where(w1).Find(&privilegeIDs)
	if err != nil || len(privilegeIDs) == 0 {
		log.Error(err)
		return privileges, err
	}
	log.Debugf("card： %s, privilege ids: %#v", cardNo, privilegeIDs)

	w2 := where.And(B.In("group_id", privilegeIDs))
	err = session.Distinct("id", "controller_id", "door_no", "open_index").Where(w2).Find(&privileges)
	if err != nil {
		log.Error(err)
		return privileges, err
	}

	return privileges, nil
}

func (ac *DacConn) addPrivilegeGroup(session *xorm.Session, cardInfo D.CardInfo) error {
	if cardInfo.GroupNo < 0 {
		return nil
	}

	cardID := strings.TrimLeft(cardInfo.CardNo, "0")
	pri := &AcsPrivilegeGroup{
		GroupID:   uuid.NewV4().String(),
		GroupName: "CARD_" + cardID,
		ItemType:  D.Person,
		Desc:      "privilege group for card",
		Modify:    D.Add,
	}

	_, err := session.InsertOne(pri)
	if err != nil {
		log.Error(err)
		return err
	}

	doors, err := ac.getDoorByIDs(cardInfo.Door)
	if err != nil {
		log.Error(err)
		return err
	}

	if len(doors) != len(cardInfo.Door) {
		return errors.New(D.EmDoorIDNotExist)
	}

	for i := 0; i < 3; i++ {
		dts, err := ac.getDoorTimeByOpenIndexAndDoor(session, cardInfo.GroupNo*3+i, doors)
		if err != nil {
			log.Error(err)
			return err
		}

		timePris := make([]*AcsTimePrivilege, 0)
		for _, dt := range dts {
			tp := &AcsTimePrivilege{
				ControllerID: dt.ControllerID,
				DoorNo:       dt.DoorNo,
				OpenIndex:    dt.OpenIndex,
				OpenID:       dt.OpenID,
				GroupID:      pri.GroupID,
				Modify:       D.Add,
			}
			timePris = append(timePris, tp)
		}

		_, err = session.Insert(timePris)
		if err != nil {
			log.Error(err)
			return err
		}
	}

	priItem := &AcsPrivilegeItem{
		GroupID:  pri.GroupID,
		ItemID:   cardID,
		ItemType: D.Person,
		Modify:   D.Add,
	}

	_, err = session.InsertOne(priItem)
	if err != nil {
		log.Error(err)
		return err
	}

	return nil
}

func (ac *DacConn) setPrivilegeGroup(session *xorm.Session, cardInfo D.CardInfo) error {
	cardID := strings.TrimLeft(cardInfo.CardNo, "0")
	pis := make([]*AcsPrivilegeItem, 0)

	err := session.Where(B.Neq{"modify": D.Delete}).Find(&pis, &AcsPrivilegeItem{ItemID: cardID, ItemType: D.Person})
	if err != nil {
		log.Error(err)
		return err
	}

	for _, pi := range pis {
		pri := &AcsPrivilegeGroup{GroupID: pi.GroupID, GroupName: "CARD_" + cardID}
		exist, err := session.Where(B.Neq{"modify": D.Delete}).Get(pri)
		if exist {
			_, err = session.Update(&AcsPrivilegeGroup{Modify: D.Delete}, pri)
			if err != nil {
				log.Error(err)
				return err
			}

			_, err = session.Update(&AcsTimePrivilege{Modify: D.Delete}, &AcsTimePrivilege{GroupID: pri.GroupID})
			if err != nil {
				log.Error(err)
				return err
			}

			_, err = session.Update(&AcsPrivilegeItem{Modify: D.Delete}, &AcsPrivilegeItem{GroupID: pri.GroupID})
			if err != nil {
				log.Error(err)
				return err
			}
		} else {
			_, err = session.Update(&AcsPrivilegeItem{Modify: D.Delete}, &AcsPrivilegeItem{GroupID: pri.GroupID})
			if err != nil {
				log.Error(err)
				return err
			}
		}
	}

	return ac.addPrivilegeGroup(session, cardInfo)
}

/*
* Record: include get_event, get_history_event
 */

//GetLatestEvent 获取新的一条事件
func (ac *DacConn) GetLatestRecord() (record AcsDoorEvent, err error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	record = AcsDoorEvent{RecordType: D.EventType}

	_, err = session.Desc("id").Get(&record)
	if err != nil {
		log.Error(err)
		return
	}
	return
}

func (ac *DacConn) GetLatestAlarm() (alarm AcsDoorEvent, err error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	alarm = AcsDoorEvent{RecordType: D.AlarmType}
	_, err = session.Desc("id").Get(&alarm)
	if err != nil {
		log.Error(err)
		return
	}

	return
}

//GetEventByIndex 获取事件
func (ac *DacConn) GetEventByIndex(recordIndex int) (records []AcsDoorEvent, err error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	records = make([]AcsDoorEvent, 0)

	if recordIndex != 0 {
		err = session.Where(B.Gt{"id": recordIndex}).Find(&records, &AcsDoorEvent{RecordType: D.EventType})
		if err != nil {
			log.Error(err)
			return
		}
	}

	return
}

//GetAlarmByIndex 获取告警
func (ac *DacConn) GetAlarmByIndex(alarmIndex int) (alarms []AcsDoorEvent, err error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	alarms = make([]AcsDoorEvent, 0)

	if alarmIndex != 0 {
		err = session.Where(B.Gt{"id": alarmIndex}).Find(&alarms, &AcsDoorEvent{RecordType: D.AlarmType})
		if err != nil {
			log.Error(err)
			return
		}
	}

	return
}

//GetHistoryEvent 获取历史记录
func (ac *DacConn) GetHistoryEvent(startTime, endTime string, doorID []int) (records []AcsDoorEvent, alarms []AcsDoorEvent, err error) {
	session := ac.dbConn.NewSession()
	defer session.Close()

	var where B.Cond
	records = make([]AcsDoorEvent, 0)
	alarms = make([]AcsDoorEvent, 0)
	data := make([]AcsDoorEvent, 0)

	doors, err := ac.getDoorByIDs(doorID)
	if err != nil {
		log.Error(err)
		return
	}

	where = B.Gte{"event_time": startTime}

	if endTime != "-1" {
		where = where.And(B.Lt{"event_time": endTime})
	}

	if len(doors) > 0 {
		temp := make(map[string]int, 0)
		ds := make([]string, 0)
		for _, dt := range doors {
			key := fmt.Sprintf("%s_%d", dt.ControllerID, dt.DoorNo)
			if _, ok := temp[key]; !ok {
				temp[key] = dt.DoorNo
				ds = append(ds, key)
			}
		}
		where = where.And(B.In(`CONCAT(controller_id, "_", door_no)`, ds))
	}
	// 	开始查询
	err = session.Where(where).Find(&data)
	if err != nil {
		log.Error(err)
		return
	}
	for _, this := range data {
		if this.RecordType != D.AlarmType {
			records = append(records, this)
		} else {
			alarms = append(alarms, this)
		}
	}
	return
}

//自动删除事件报警数据
func (ac *DacConn) CheckEventDel() error {
	session := ac.dbConn.NewSession()
	defer session.Close()
	ResStr := ""
	MaxNum := int64(10000) //最大存储数
	DelNum := MaxNum / 2   //超出最大存储数后删除的数量
	EventNum, err := session.Count(&AcsDoorEvent{RecordType: D.EventType})
	if err != nil {
		return err
	}
	AlarmNum, err := session.Count(&AcsDoorEvent{RecordType: D.AlarmType})
	if err != nil {
		return err
	}
	if EventNum > MaxNum {
		DelDbNum, err := session.Asc("id").Limit(int(DelNum)).Delete(&AcsDoorEvent{RecordType: D.EventType})
		if err != nil {
			return err
		}
		ResStr += fmt.Sprintf(" EventNum > %d, Del Event num: %d", MaxNum, DelDbNum)
		log.Info(ResStr)
	}
	if AlarmNum > MaxNum {
		DelDbNum, err := session.Asc("id").Limit(int(DelNum)).Delete(&AcsDoorEvent{RecordType: D.AlarmType})
		if err != nil {
			return err
		}
		ResStr += fmt.Sprintf(" AlarmNum > %d, Del Alarm num: %d", MaxNum, DelDbNum)
		log.Info(ResStr)
	}
	fmt.Println("EventNum:", EventNum, "AlarmNum:", AlarmNum, ResStr)
	return nil
}
